package testApplets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Vector;


import peasy.PeasyCam;
import processing.core.PApplet;
import simpleGeom.AbstractFace;
import simpleGeom.BasicMesh;
import simpleGeom.Bounds3D;
import simpleGeom.Box3D;
import simpleGeom.Face3D;
import simpleGeom.HasPos3D;
import simpleGeom.HasPos3DXComparator;
import simpleGeom.HasPos3DYComparator;
import simpleGeom.HasPos3DZComparator;
import simpleGeom.Node;
import simpleGeom.SimpleTriangle;
import simpleGeom.Vec3D;

public class ImplatCone  {
	BasicMesh mesh=new BasicMesh();
	ArrayList<AbstractFace>faces=new ArrayList<AbstractFace>();
	Box3D box;
	int nSegments=32;// durch 4 teilbar
	float coneOffset=-10;
	float coneHeight=-30;
	float coneRadius=100;
	float dim=32;
	float yTol=0.01f;
	public void initExample(){
		Node[][] grid=new Node[20][20];
		for (int x=0;x<20;x++){
			for (int y=0;y<20;y++){
				Node node=new Node(x*30-300,y*30-300);
				mesh.nodes.add(node);
				grid[x][y]=node;
			}
		}
		Vector<SimpleTriangle> gridFaces=new Vector<SimpleTriangle>();
		for (int x=0;x<grid.length-1;x++){
			for (int y=0;y<grid[x].length-1;y++){
				Node n1=grid[x][y];
				Node n2=grid[x+1][y];
				Node n3=grid[x+1][y+1];
				Node n4=grid[x][y+1];
				SimpleTriangle f1=new SimpleTriangle(n1,n2,n3);
				mesh.faces.add(f1);
				gridFaces.add(f1);
				SimpleTriangle f2=new SimpleTriangle(n3,n4,n1);
				gridFaces.add(f2);
				mesh.faces.add(f2);
			}
		}
		implement(mesh,0,0,0,100,-30,-10,dim);
	
	}
	
	
	public void implement(BasicMesh mesh,float x,float y,float z, float coneRadius,float coneHeight,float coneOffset,float dim){
		this.mesh=mesh;
		this.coneHeight=coneHeight;
		this.coneOffset=coneOffset;
		this.coneRadius=coneRadius;
		this.dim=dim;
		box=new Box3D(x-coneRadius-dim,y-yTol,z-coneRadius-dim,x+coneRadius+dim,y+yTol,z+coneRadius+dim);
		System.out.println("before: "+mesh.nodes.size());
		mesh.remove(box.getOffsetBox(dim));
		System.out.println("after: "+mesh.nodes.size());
		faces=new ArrayList<AbstractFace>();
		faces.addAll(getCone(x,y,z,coneRadius,nSegments));
		for (int i=0;i<faces.size();i++){
			SimpleTriangle st=(SimpleTriangle) faces.get(i);
			st.invert();
		}
		mesh.addFacesAndNodes(faces);
	}
	
	
	
	public void sortAndConnectList(ArrayList<HasPos3D>positions,ArrayList<HasPos3D>rect){
		float tol=0;
		Bounds3D b3d=new Bounds3D();
		b3d.addAll(positions);
		ArrayList<HasPos3D>nodesTop=new ArrayList<HasPos3D>();
		ArrayList<HasPos3D>nodesLow=new ArrayList<HasPos3D>();
		ArrayList<HasPos3D>nodesRight=new ArrayList<HasPos3D>();
		ArrayList<HasPos3D>nodesLeft=new ArrayList<HasPos3D>();
		for (int i=0;i<positions.size();i++){
			HasPos3D p=positions.get(i);
			if (Math.abs(p.getZ()-b3d.getZ1())<=tol){
				nodesLow.add(p);
			}
			 if (Math.abs(p.getX()-b3d.getX1())<=tol){
				nodesLeft.add(p);
			}
			 if (Math.abs(p.getZ()-b3d.getZ2())<=tol){
				nodesTop.add(p);
			}
			 if (Math.abs(p.getX()-b3d.getX2())<=tol){
				nodesRight.add(p);
			}
		}
		Collections.sort(nodesTop, new HasPos3DXComparator());
		Collections.sort(nodesLow, new HasPos3DXComparator());
		Collections.reverse(nodesTop);
		
		Collections.sort(nodesRight, new HasPos3DZComparator());
		Collections.sort(nodesLeft, new HasPos3DZComparator());
		Collections.reverse(nodesLeft);
		
		for (int i=0;i<rect.size();i++){
			HasPos3D corner=rect.get(i);
			HasPos3D corner2=rect.get((i+1)%4);
			ArrayList<HasPos3D>cList=nodesTop;
			if(i==0){
				cList=nodesLeft;
			}
			else if(i==1){
				cList=nodesLow;
			}
			else if(i==2){
				cList=nodesRight;
			}
			else if(i==3){
				cList=nodesTop;
			}
			for (int j=0;j<cList.size()-1;j++){
				HasPos3D p0=cList.get(j);
				HasPos3D p1=cList.get(j+1);
				SimpleTriangle tri=new SimpleTriangle(corner,p0,p1);
				faces.add(tri);
			}
			SimpleTriangle tri=new SimpleTriangle(corner,cList.get(cList.size()-1),corner2);
			faces.add(tri);
		}
	}
	
	public Vector<HasPos3D> getCircle(float x,float y, float z, float radius,int nSegs){
		Vector<HasPos3D> nodes=new Vector<HasPos3D>();
		float dAngle=(float) (Math.PI*2f)/nSegs;
		for (int i=0;i<nSegs;i++){
			float cX=radius*(float)Math.cos(i*dAngle)+x;
			float cZ=radius*(float)Math.sin(i*dAngle)+z;
			Node node=new Node(cX,y,cZ);
			nodes.add(node);
		}
		return nodes;
	}
	
	public Vector<SimpleTriangle> getCone(float x,float y, float z, float r,int nSegs){
		float rO=r+dim;
		ArrayList<HasPos3D>bounds=new ArrayList<HasPos3D>();
		bounds.add(new Node(x-rO,y,z-rO));
		bounds.add(new Node(x+rO,y,z-rO));
		bounds.add(new Node(x+rO,y,z+rO));
		bounds.add(new Node(x-rO,y,z+rO));
		Vector<HasPos3D>circle1=getCircle(x,y,z,r,nSegs);
		Vector<HasPos3D>circle2=getCircle(x,y+coneHeight,z,r+coneOffset,nSegs);
		Vector<SimpleTriangle>faces=new Vector<SimpleTriangle>();
		for (int i=0;i<circle1.size();i++){
			HasPos3D p1=circle1.get(i);
			HasPos3D p2=circle1.get((i+1)%circle1.size());
			HasPos3D b1=circle2.get(i);
			HasPos3D b2=circle2.get((i+1)%circle1.size());
			SimpleTriangle tri1=new SimpleTriangle(p1,p2,b1);
			faces.add(tri1);
			SimpleTriangle tri2=new SimpleTriangle(b2,b1,p2);
			faces.add(tri2);
		}
		HasPos3D center=new Node(x,y+coneHeight,z);
		for (int i=0;i<circle2.size();i++){
			HasPos3D p1=circle2.get(i);
			HasPos3D p2=circle2.get((i+1)%circle1.size());
			SimpleTriangle tri=new SimpleTriangle(p1,p2,center);
			faces.add(tri);
		}
		for (int i=0;i<bounds.size();i++){
			Node n=(Node) bounds.get(i);
			int jStart=i*circle1.size()/4+2*circle1.size()/4;
			int jEnd=jStart+circle1.size()/4;
			for (int j=jStart;j<jEnd;j++){
				HasPos3D n1=circle1.get(j%circle1.size());
				HasPos3D n2=circle1.get((j+1)%circle1.size());
				SimpleTriangle tri=new SimpleTriangle(n2,n1,n);
				faces.add(tri);
			}
		}
		for (int i=0;i<bounds.size();i++){
			Node n1=(Node) bounds.get(i);
			Node n2=(Node) bounds.get((i+1)%bounds.size());
			int j=i*circle1.size()/4+3*circle1.size()/4;
			HasPos3D n=circle1.get(j%circle1.size());
			SimpleTriangle tri=new SimpleTriangle(n,n1,n2);
			faces.add(tri);
		}
		ArrayList<HasPos3D>positions=mesh.getNodes(box.getOffsetBox(dim));
		float posY=positions.get(0).getY();
		for (int i=0;i<circle1.size();i++){
			HasPos3D p1=circle1.get(i);
			p1.setY(posY);
		}
		for (int i=0;i<bounds.size();i++){
			HasPos3D p1=bounds.get(i);
			p1.setY(posY);
		}
		for (int i=0;i<circle2.size();i++){
			HasPos3D p1=circle2.get(i);
			p1.setY(posY+coneHeight);
		}
		center.setY(posY+coneHeight);
		System.out.println("positions: "+positions.size());
		sortAndConnectList(positions,bounds);
		return faces;
	}
}
